/*
 * Copyright 2009 Tran Nhut Trung.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package org.eclipse.core.databinding.observable.gwt.internal;


import com.google.gwt.user.client.ui.Widget;

import java.util.ArrayList;

import java.util.Iterator;
import java.util.List;

import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.gwt.IWidgetObservable;
import org.eclipse.core.databinding.observable.gwt.internal.widgets.ScrollTable;
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
import org.eclipse.core.databinding.observable.list.ObservableList;

public abstract class DataTableObservableList extends ObservableList implements IWidgetObservable{
  private ScrollTable grid;
  protected boolean updating = false; 
  
  public DataTableObservableList(ScrollTable grid, Object elementType) {
    this(Realm.getDefault(), grid, elementType);
  }

  public DataTableObservableList(Realm realm, ScrollTable grid, Object elementType) {
    super(realm, new ArrayList(), elementType);
    
    this.grid = grid;
  }

  public Widget getWidget() {
    return grid;
  }  

  public void add(int index, Object element) {
    updating = true;
    try {
      wrappedList.add(index, element);
      grid.getBody().insertRow(index);
      setRow(index, element, null);
      fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
          index, true, element)));
    } finally {
      updating = false;
    }
  }

  public void clear() {
    updating = true;
    try {
      List diffEntries = new ArrayList();
      for (Iterator it = wrappedList.iterator(); it.hasNext();) {
        Object o = it.next();
        diffEntries.add(Diffs.createListDiffEntry(0, false, o));
      }
      wrappedList.clear();
      clearTable();
      fireListChange(Diffs.createListDiff((ListDiffEntry[])diffEntries
          .toArray(new ListDiffEntry[diffEntries.size()])));
    } finally {
      updating = false;
    }
  }
  
  public Object set(int index, Object element) {
    getterCalled();
    updating = true;
    try {
      Object oldElement = wrappedList.set(index, element);
      setRow(index, element, oldElement);
      fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
          index, false, oldElement), Diffs.createListDiffEntry(index,
          true, element)));
      return oldElement;
    } finally {
      updating = false;
    }
  }

  public Object remove(int index) {
    getterCalled();
    updating = true;
    try {
      Object oldElement = wrappedList.remove(index);
      removeRow(index, oldElement);
      fireListChange(Diffs.createListDiff(Diffs.createListDiffEntry(
          index, false, oldElement)));
      return oldElement;
    } finally {
      updating = false;
    }
  }

  protected void clearTable(){
    grid.getBody().clear();
  }

  protected abstract void setRow(int row, Object element, Object oldElement);

  protected void removeRow(int index, Object oldElement){
    grid.getBody().removeRow(index);
  }
}
